﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;

namespace SnelsteRoute
{
    public class ConfigurationLoader
    {
        private const String ConfigFolder = "Config";
        private const String SearchPattern = "*.txt";

        public static void Load()
        {
            Models.GetInstance().LoadingProgress = 0;

            var path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
            path = new Uri(path).AbsolutePath;
            path = Path.Combine(path, ConfigFolder);
            var files = Directory.GetFiles(path, SearchPattern);
            var configs = new List<Configuration>();

            if (files.Length == 0)
                throw new Exception("No config files found in folder  + path");

            var percentagePerFile = 100/files.Length;


            foreach (var file in files)
            {
                var config = LoadFile(file); 
                configs.Add(config);
                VerifyConfig(config);

                Models.GetInstance().LoadingProgress += percentagePerFile;
            }

            Models.GetInstance().Configurations = configs;
            Models.GetInstance().LoadingProgress = 100;
        }

        private static Configuration LoadFile(string filePath)
        {

            var stream = File.OpenText(filePath);
            var content = stream.ReadToEnd();
            stream.Close();

            var seperatorIndex = content.IndexOf('#');

            if (seperatorIndex < 0)
                throw new Exception("Config file invalid, seperator '#' between description and aspects not found.");

            var config = new Configuration()
            {
                Description = ReadDescription(content, seperatorIndex),
                Aspects = ReadAspects(content, seperatorIndex)
            };

            config.ResolveRelations();            

            return config;
        }

        private static List<Aspect> ReadAspects(string content,Int32 seperatorIndex)
        {
            var aspectString = content.Substring(seperatorIndex+2);
            aspectString = aspectString.Trim('\r', '\n', ' ');
            aspectString = aspectString.Replace("\r\n", "\n");
            var aspectLines = aspectString.Split('\n');

            var aspects = new List<Aspect>();

            foreach(var line in aspectLines)
                aspects.Add( ReadAspect(line));

            return aspects;
        }

        private static Aspect ReadAspect(string line)
        {
            var equalsIndex = line.IndexOf('=');

            if (equalsIndex < 0)
                throw new Exception("Line does not contain an equals sign (=) " + line );

            var aspectName = line.Substring(0, equalsIndex);
            String[] aspects;
            var restText = line.Substring(equalsIndex + 1);

            if (!String.IsNullOrEmpty(restText))
                aspects = restText.Split('+');
            else
                aspects = new string[]{};

            return new Aspect(aspectName,aspects);
        }

        private static string ReadDescription(string content, Int32 seperatorIndex)
        {
            return content.Substring(0, seperatorIndex).Trim(' ', '\n', '\r', '\t');
        }

        private static void VerifyConfig(Configuration config)
        {
            foreach (var aspect in config.Aspects)
            {
                if (!aspect.Validate())
                    throw new Exception("Invalid aspect found, " + aspect.ToString());
            }
        }
    }
}
